<template>
    <div>
        <div v-if="props.url" class="success">
            <el-image class="img" :src="url" alt="" />
            <div class="msk">
                <div class="btn_box">
                    <div class="btn_icon">
                        <el-icon @click="onPictureCardPreview"><zoom-in /></el-icon>
                    </div>
                    <div class="btn_icon">
                        <el-icon @click="onRemove"><Delete /></el-icon>
                    </div>
                </div>
            </div>
        </div>
        <el-upload
            v-else
            action=""
            :accept="fileType"
            list-type="picture-card"
            :show-file-list="false"
            :auto-upload="false"
            :on-change="onUploadChange">
            <el-icon class="plus_icon"><Plus /></el-icon>
        </el-upload>
        <div class="tip">建议尺寸1:1，图片大小限制10M，格式限制jpg/jpeg/png</div>
        <el-dialog top="8vh" title="查看图片" v-model="state.dialogVisible">
            <img w-full :src="props.url" alt="Preview Image" class="preview-img" />
        </el-dialog>
    </div>
</template>

<script setup>
import request from '@/request';
import { reactive, ref } from 'vue';
import { Plus } from '@element-plus/icons-vue';
import { ElMessage } from 'element-plus';

const props = defineProps({
    url: { type: String }
});
const emit = defineEmits(['change']);
const fileType = '.jpg,.jpeg,.png';
const state = reactive({
    dialogVisible: false
});

const onCrop = async (blobUrl, fileName) => {
    return new Promise(resolve => {
        const img = new Image();
        img.src = blobUrl;
        const canvas = document.createElement('canvas');
        const ctx = canvas.getContext('2d');

        // base64地址图片加载完毕后
        img.onload = function () {
            // 图片原始尺寸
            let originWidth = this.width;
            let originHeight = this.height;
            // 最终要裁剪到的尺寸
            let maxWidth = 100,
                maxHeight = 100; //裁剪成120*120的大小
            //目标尺寸 targetWidth
            let targetWidth = originWidth,
                targetHeight = originHeight;
            // 先取最短边（长或者宽）
            let xStart, yStart; //开始裁剪x轴的坐标，和y轴的坐标
            if (originWidth > originHeight) {
                // 判断最短边，因为我们要裁的最终的图片是长宽相等的，所以裁剪时取最短的
                targetWidth = originHeight;
                targetHeight = originHeight;
                xStart = (originWidth - targetWidth) / 2; // 裁剪x轴的坐标,因为是居中裁剪，所以是取中间开始截取
                yStart = (originHeight - targetHeight) / 2;
            } else {
                targetWidth = originWidth;
                targetHeight = originWidth;
                xStart = (originWidth - targetWidth) / 2;
                yStart = (originHeight - targetHeight) / 2;
            }
            // 截取成图片最小宽度的尺寸
            maxWidth = targetWidth;
            maxHeight = targetHeight;
            canvas.width = maxWidth;
            canvas.height = maxHeight;
            ctx.fillStyle = '#fff';
            ctx.fillRect(0, 0, maxWidth, maxHeight);
            ctx.drawImage(img, xStart, yStart, targetWidth, targetHeight, 0, 0, maxWidth, maxHeight);
            // canvas转为blob并上传
            canvas.toBlob(
                blob => {
                    const newFile = new File([blob], fileName, { type: 'image/jpeg' });
                    resolve(newFile);
                },
                'image/jpeg',
                0.9
            );
        };
    });
};
const onUploadChange = async file => {
    const suffix = file.raw.name.split('.').pop().toLowerCase();
    if (!fileType.includes(suffix)) {
        ElMessage.error('请上传jpg、png、jpeg格式的图片');
        return;
    }
    const newFile = await onCrop(file.url, file.name);
    if (newFile.size / 1024 / 1024 > 10) {
        ElMessage.error('图片大小应小于10M');
        return;
    }
    const params = new FormData();
    params.append('file', newFile);
    const { data } = await request('fileUploadServ', params);
    emit('change', data.url);
};
const onRemove = () => {
    emit('change', '');
};

const onPictureCardPreview = () => {
    state.dialogVisible = true;
};
</script>
<style lang="scss" scoped>
:deep(.el-upload) {
    width: 70px;
    height: 70px;
    position: relative;
    .plus_icon {
        color: #ff6b00;
    }
}
.preview-img {
    width: 100%;
    border-style: none;
}
.tip {
    font-size: 12px;
    line-height: 40px;
    width: 400px;
    word-break: break-all;
    color: #909399;
}
.success {
    position: relative;
    width: 70px;
    height: 70px;
    border-radius: 6px;
    box-sizing: border-box;
    border: 1px dashed#cdd0d6;
    cursor: pointer;
    overflow: hidden;

    .img {
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        height: 100%;
    }
    .msk {
        display: none;
        position: absolute;
        width: 100%;
        height: 100%;
        left: 0;
        top: 0;
        cursor: default;
        color: #fff;
        background-color: var(--el-overlay-color-lighter);
        transition: opacity var(--el-transition-duration);
        .btn_box {
            width: 100%;
            height: 100%;
            font-size: 26px;
            cursor: default;
            display: inline-flex;
            justify-content: center;
            align-items: center;
            column-gap: 8px;
            .btn_icon {
                cursor: pointer;
            }
        }
    }

    &:hover {
        border-color: #ff6b00;
        .msk {
            display: block;
        }
    }
}
</style>
